package com.xgk.boot.module.core.service.truck;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mzt.logapi.context.LogRecordContext;
import com.mzt.logapi.starter.annotation.LogRecord;
import com.xgk.boot.framework.common.constant.ElmConstant;
import com.xgk.boot.framework.common.constant.ErrorCodeConstants;
import com.xgk.boot.framework.common.context.ElmOrderThreadContext;
import com.xgk.boot.framework.common.exception.util.ServiceExceptionUtil;
import com.xgk.boot.framework.common.util.json.JsonUtils;
import com.xgk.boot.framework.common.util.object.BeanUtils;
import com.xgk.boot.framework.security.core.util.SecurityFrameworkUtils;
import com.xgk.boot.module.core.common.RedisHandlerService;
import com.xgk.boot.module.core.controller.admin.truck.vo.OrderAddressVO;
import com.xgk.boot.module.core.controller.admin.truck.vo.OrderDataSaveVO;
import com.xgk.boot.module.core.controller.admin.truck.vo.SelectedRateVO;
import com.xgk.boot.module.core.dal.dto.TruckOrderDto;
import com.xgk.boot.module.core.dal.entity.customer.CustomerDO;
import com.xgk.boot.module.core.dal.entity.product.ProductDO;
import com.xgk.boot.module.core.dal.entity.truck.TruckOrderAddressDO;
import com.xgk.boot.module.core.dal.entity.truck.TruckOrderBoxDO;
import com.xgk.boot.module.core.dal.entity.truck.TruckOrderLogDO;
import com.xgk.boot.module.core.dal.entity.truck.TruckOrdersDO;
import com.xgk.boot.module.core.dal.iservice.truck.TruckOrderQuotationService;
import com.xgk.boot.module.core.dal.mapper.product.ProductMapper;
import com.xgk.boot.module.core.dal.mapper.truck.TruckOrderAddressMapper;
import com.xgk.boot.module.core.dal.mapper.truck.TruckOrderBoxMapper;
import com.xgk.boot.module.core.dal.mapper.truck.TruckOrdersMapper;
import com.xgk.boot.module.core.dal.redis.RedisKeyConstants;
import com.xgk.boot.module.core.enums.biz.AddressTypeEnum;
import com.xgk.boot.module.core.enums.biz.ChangeTypeEnum;
import com.xgk.boot.module.core.enums.biz.OrderStatusEnum;
import com.xgk.boot.module.core.logistics.service.mothership.dto.OrderQuotationDto;
import com.xgk.boot.module.core.logistics.service.mothership.dto.QuotationChoiceDto;
import com.xgk.boot.module.core.logistics.service.mothership.response.InvalidFieldsRequiredDto;
import com.xgk.boot.module.core.service.customer.CustomerServiceImpl;
import com.xgk.boot.module.core.service.product.ProductServiceImpl;
import com.xgk.boot.module.core.util.CommonUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.xgk.boot.module.core.enums.LogRecordConstants.*;

@Slf4j
@Service
public class TruckOrderQuotationServiceImpl extends ServiceImpl<TruckOrdersMapper, TruckOrdersDO> implements TruckOrderQuotationService {

    @Resource
    private ProductServiceImpl productService;
    @Resource
    private TruckOrdersMapper     truckOrdersMapper;
    @Resource
    private TruckOrderBoxMapper truckOrderBoxMapper;
    @Resource
    private TruckOrderAddressMapper truckOrderAddressMapper;
    @Resource
    private CustomerServiceImpl customerService;
    @Resource
    private RedisHandlerService redisHandlerService;
    @Resource
    private TruckOrderLogServiceImpl orderLogService;
    public static final DateTimeFormatter FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");


    public TruckOrderDto prepareOrderDto(OrderDataSaveVO saveData) {
        TruckOrdersDO ordersDO = new TruckOrdersDO();
        ordersDO.setOrderCode(CommonUtil.getNewOrderCode());
        ordersDO.setReferenceNo(saveData.getReferenceNo());
        ordersDO.setCreateType("web");

        SelectedRateVO quote = saveData.getQuote();
        if(quote!=null){
            ordersDO.setProductCode(quote.getProductCode());
            ordersDO.setSpCode(quote.getSpCode());
            saveData.setProductCode(quote.getProductCode());
        }



//        ProductDO productDO = productService.getProductCacheByCode(saveData.getProductCode());
//        if(productDO == null) {
//            throw new RuntimeException("商品不存在");
//        }
//        ordersDO.setSpCode(productDO.getPrSpApiPd());

        String pickReadyDatetime = saveData.getPickReadyDatetime();
        String detailPick =  saveData.getShipperAddress().getPickReadyDatetime();
        if(pickReadyDatetime == null && detailPick != null) {
          pickReadyDatetime = detailPick;
        }
        if(detailPick !=null){
            pickReadyDatetime = detailPick;
        }
        if(pickReadyDatetime==null) {
            throw new RuntimeException("请选择提货时间");
        }

        String customer_code = SecurityFrameworkUtils.getLoginUser().getUsername();
        ordersDO.setCustomerCode(customer_code);
        ordersDO.setOrderType(0);
//        CustomerDO customerDO = customerService.selectByCustomerCode(customer_code);
//        ordersDO.setCustomerId(customerDO.getId());


        TruckOrderDto dto = new TruckOrderDto();
        dto.setTruckOrdersDO(ordersDO);

        List<TruckOrderBoxDO> boxs = saveData.getBoxs().stream().map(box -> {
            TruckOrderBoxDO boxDO = new TruckOrderBoxDO();
            BeanUtils.copyProperties(box, boxDO);
            return boxDO;
        }).toList();
        dto.setOrderBoxDOList(boxs);

        TruckOrderAddressDO shipperAddressDO = transform(saveData.getShipperAddress(), saveData.getShipperAddressDT());

//        Instant instant = Instant.parse(pickReadyDatetime);
//        // 2. 转换为系统默认时区的LocalDateTime
//        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
//        // 3. 丢弃秒和纳秒部分
//        LocalDateTime truncatedDateTime = localDateTime.withSecond(0).withNano(0);
//        shipperAddressDO.setPickReadyDatetime(truncatedDateTime);
        shipperAddressDO.setPickReadyDatetime(LocalDateTime.parse(pickReadyDatetime, FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE));
        dto.setShipperAddressDO(shipperAddressDO);

        TruckOrderAddressDO deliveryAddressDO = transform(saveData.getDeliveryAddress(), saveData.getDeliveryAddressDT());
        dto.setDeliveryAddressDO(deliveryAddressDO);

        return dto;

    }

    private TruckOrderAddressDO transform(OrderAddressVO shipperAddress, String shipperAddressDT) {
        TruckOrderAddressDO addressDO = new TruckOrderAddressDO();
        BeanUtils.copyProperties(shipperAddress, addressDO);
        parseUSAddressToDO(shipperAddressDT, addressDO);
        return addressDO;
    }

    /**
     * 解析美国地址并填充到 TruckOrderAddressDO 对象
     *
     * @param fullAddress 完整地址字符串，如 "938 E Belmont St, Ontario, CA 91761"
     * @param addressDO   要填充的地址数据对象
     */
    public static void parseUSAddressToDO(String fullAddress, TruckOrderAddressDO addressDO) {
        if(addressDO == null) {
            throw new IllegalArgumentException("Address DO object cannot be null");
        }

        // 正则表达式匹配美国地址格式：街道地址, 城市, 州 邮编
        Pattern pattern = Pattern.compile("^(.*?),\\s*(.*?),\\s*([A-Z]{2})\\s*(\\d{5}(?:-\\d{4})?)$");
        Matcher matcher = pattern.matcher(fullAddress.trim());

        if(matcher.matches()) {
            // 解析街道地址部分
            String streetAddress = matcher.group(1).trim();
            parseStreetAddress(streetAddress, addressDO);

            // 城市
            addressDO.setOaCity(matcher.group(2).trim());

            // 州代码
            addressDO.setOaState(matcher.group(3).trim());

            // 邮编（如果需要也可以存储）
             addressDO.setOaPostcode(matcher.group(4));
        } else {
            throw new IllegalArgumentException("Invalid US address format: " + fullAddress);
        }
    }

    private static void parseStreetAddress(String streetAddress, TruckOrderAddressDO addressDO) {
        // 分割街道地址和单元号（如果有）
        String[] parts = streetAddress.split("\\s+#|\\s+Unit\\s+|\\s+Apt\\s+", 2);

        // 街道地址部分
        addressDO.setOaStreetAddress1(parts[0].trim());

        // 如果有单元/门牌号
        if(parts.length > 1) {
            addressDO.setOaUnit(parts[1].trim());
        }

        // 如果有第二行地址（这里简单处理，实际情况可能更复杂）
        String[] streetParts = parts[0].split(",", 2);
        if(streetParts.length > 1) {
            addressDO.setOaStreetAddress1(streetParts[0].trim());
            addressDO.setOaStreetAddress2(streetParts[1].trim());
        }
    }


    @Transactional(rollbackFor = Exception.class)
    @LogRecord(type = SYSTEM_ORDER_TYPE, subType = SYSTEM_ORDER_CREATE_TYPE, bizNo = "{{#order.orderCode}}",
            success = SYSTEM_ORDER_CREATE_SUCCESS)
    public TruckOrderDto saveOrder(TruckOrderDto dto) {
        TruckOrdersDO truckOrdersDO = dto.getTruckOrdersDO();
        truckOrdersDO.setOrderStatus(OrderStatusEnum.SUBMITTED.getValue());
        truckOrdersMapper.insert(truckOrdersDO);

        List<TruckOrderBoxDO> orderBoxDOList = dto.getOrderBoxDOList();
        Integer index=1;
        for (TruckOrderBoxDO boxDO : orderBoxDOList) {
            boxDO.setOrderCode(truckOrdersDO.getOrderCode());
            if(boxDO.getBoxCode() == null) {
                boxDO.setBoxCode(index.toString());
                index++;
            }
        }
        truckOrderBoxMapper.insertBatch(orderBoxDOList);

        TruckOrderAddressDO shipperAddressDO = dto.getShipperAddressDO();
        shipperAddressDO.setOrderCode(truckOrdersDO.getOrderCode());
        shipperAddressDO.setOaType(AddressTypeEnum.PICKUP.getValue());
        truckOrderAddressMapper.insert(shipperAddressDO);
        TruckOrderAddressDO deliveryAddressDO = dto.getDeliveryAddressDO();
        deliveryAddressDO.setOrderCode(truckOrdersDO.getOrderCode());
        deliveryAddressDO.setOaType(AddressTypeEnum.DELIVERY.getValue());
        truckOrderAddressMapper.insert(deliveryAddressDO);
        LogRecordContext.putVariable("order", truckOrdersDO);
        addTruckOrderCreatLog(truckOrdersDO);
        //记录订单状态变化日志
        return dto;
    }


    /**
     * 下单前置检测
     * 根据选择报价，查看是否报价订单是否有不合规的部分
     * @param orderQuotationDto
     */
    public void preOrderCheck(OrderQuotationDto orderQuotationDto){
        //检测询价是否存在警告信息
        QuotationChoiceDto choiceQuotationDto = orderQuotationDto.getChoiceQuotationDto();
        if(choiceQuotationDto ==null){
            return;
        }
        Object obj = redisHandlerService.get(String.format(RedisKeyConstants.QUOTATION_KEY_WARNING, choiceQuotationDto.getQuoteId()));
        List<InvalidFieldsRequiredDto> invalidFieldsRequiredDtos = JsonUtils.parseObjectToList(obj, InvalidFieldsRequiredDto.class);
        if (invalidFieldsRequiredDtos==null){
            return;
        }
        List<String> warns = new ArrayList<>();
        for (InvalidFieldsRequiredDto invalidFieldsRequiredDto : invalidFieldsRequiredDtos) {
            if(invalidFieldsRequiredDto.getRequired()){
                warns.add(invalidFieldsRequiredDto.getErrorMessage());
            }
        }
        if(warns.isEmpty()){
            return;
        }
        throw ServiceExceptionUtil.exception(ErrorCodeConstants.REQUEST_EXCEPTION, formatListEnhanced(warns));
    }


    public static String formatListEnhanced(List<String> list) {
        if (list == null || list.isEmpty()) {
            return "";
        }

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < list.size(); i++) {
            String item = list.get(i);
            if (item == null) {
                item = ""; // 处理null值
            }
            // 替换可能影响格式的特殊字符
            item = item.replace(";", ",").replace(".", "·");

            sb.append(i + 1).append(".").append(item.trim());
            if (i < list.size() - 1) {
                sb.append(";");
            }
        }
        return sb.toString();
    }

    /**
     * 记录订单创建日志
     *
     * @param newOrder
     * @return
     */
    private Boolean addTruckOrderCreatLog(TruckOrdersDO newOrder) {
        TruckOrderLogDO orderLog = new TruckOrderLogDO();
        orderLog.setOpType("add");
        orderLog.setOrderStatusTo(newOrder.getOrderStatus());
        orderLog.setOrderCode(newOrder.getOrderCode());
        orderLog.setOlType(ChangeTypeEnum.CONTENT.getValue());
        Object ip = ElmOrderThreadContext.get(ElmConstant.REQUEST_IP);
        if(ip != null) {
            orderLog.setOlIp(ip.toString());
        } else {
            orderLog.setOlIp("system");
        }
        orderLog.setOrderId(newOrder.getOrderId());
        orderLog.setOrderStatusTo(newOrder.getOrderStatus());
        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
        if(loginUserId != null) {
            orderLog.setUserId(loginUserId);
            orderLog.setUserName(SecurityFrameworkUtils.getLoginUserName());
        }else {
            orderLog.setUserId(0L);
            orderLog.setUserName("system");
        }
        orderLog.setOlComments("create order");
        return orderLogService.save(orderLog);
    }

    public OrderQuotationDto getQuote(TruckOrdersDO ordersDO,OrderDataSaveVO saveData) {
        OrderQuotationDto orderQuotationDto = new OrderQuotationDto();
        orderQuotationDto.setOrderCode(ordersDO.getOrderCode());
        orderQuotationDto.setReferenceNo(ordersDO.getReferenceNo());


        SelectedRateVO quote = saveData.getQuote();

        orderQuotationDto.setProductCode(quote.getProductCode());
        orderQuotationDto.setSpCode(quote.getSpCode());

        orderQuotationDto.setEstimatedPrice(quote.getPrice());

        QuotationChoiceDto quotationChoiceDto = new QuotationChoiceDto();
        quotationChoiceDto.setQuoteId(quote.getQuoteId());
        quotationChoiceDto.setRateId(quote.getId());
        orderQuotationDto.setChoiceQuotationDto(quotationChoiceDto);
        return orderQuotationDto;
    }

}
